/*******************************************************************************
*  file    : calcplotwidget.cpp
*  created : 28.08.2014
*  author  : Slyshyk Oleksiy (alexSlyshyk@gmail.com)
*******************************************************************************/

#include "calcplotwidget.hpp"
#include "ui_calcplotwidget.h"
#include "plot.hpp"
#include "utils.hpp"

#include "dataobject/dataobject.hpp"
#include <interfaces.hpp>
#include <solutions.hpp>

#include <QBoxLayout>

#include <QApplication>
#include <utils.hpp>
#include <qlogger.hpp>
namespace
{
QLogger * l = QLoggerEngine::getLogger("Core");
}


CalcPlotWidget::CalcPlotWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CalcPlotWidget)
{
    ui->setupUi(this);
    QVBoxLayout* lay = new QVBoxLayout(this);
    this->setLayout(lay);
    plot_ = new TPlot(this);
    lay->addWidget(plot_);
}

CalcPlotWidget::~CalcPlotWidget()
{
    delete ui;
}

void CalcPlotWidget::clearPlots()
{
    plot_->clear();
}

void CalcPlotWidget::findPatterns(const DataObject* data)
{
    if(data == nullptr)
        return;

    if(data->dataL().data()->data.size())
        {
            QVector<QPointF> series;
            series.resize(data->dataL().data()->data.size());
            for(size_t i = 0; i < data->dataL().data()->data.size(); ++i)
                series[i] = QPointF(i/*/data->dataL().data()->sampleRate*/,data->dataL().data()->data[i].real());

            QVector<QPointF> series_mid;
            series_mid.resize(series.size());
            size_t pos_st, pos_end;
            pos_st = 0; pos_end = 10;
            while(static_cast<int>(pos_end) < series_mid.size())
                {
                    double sum = 0.;
                    for(size_t i = pos_st; i < pos_end; ++i)
                        sum += series[i].y();
                    for(size_t i = pos_st; i < pos_end; ++i)
                        series_mid[i] = QPointF(i,sum / (pos_end - pos_st));

                    pos_st  += 10;
                    pos_end += 10;
                }

            plot_->addCurve(data->dataL().data()->name, series);
            //plot_->addCurve(data->dataL().data()->name + "mid", series_mid);
        }
    auto left_res = signal_utils::find_patterns(data->dataL().data()->data);
    logInfo(l) << "Left  pulse["<<left_res[0]<<","<<left_res[1]<<"]";
    plot_->setZone(left_res[0],left_res[1],"left");
    QwtPlotZoneItem* zone = plot_->zone("left") ;
    zone->setPen( Qt::darkGray );
    zone->setBrush( QColor( "#66CCFF") );
    if(data->dataR().data()->data.size())
        {
            QVector<QPointF> series;
            series.resize(data->dataR().data()->data.size());
            for(size_t i = 0; i < data->dataR().data()->data.size(); ++i)
                series[i] = QPointF(i/*/data->dataR().data()->sampleRate*/,data->dataR().data()->data[i].real());

            QVector<QPointF> series_mid;
            series_mid.resize(series.size());
            size_t pos_st, pos_end;
            pos_st = 0; pos_end = 10;
            while(static_cast<int>(pos_end) < series_mid.size())
                {
                    double sum = 0.;
                    for(size_t i = pos_st; i < pos_end; ++i)
                        sum += series[i].y();
                    for(size_t i = pos_st; i < pos_end; ++i)
                        series_mid[i] = QPointF(i,sum / (pos_end - pos_st));

                    pos_st  += 10;
                    pos_end += 10;
                }

            plot_->addCurve(data->dataR().data()->name, series);
            //plot_->addCurve(data->dataR().data()->name + "mid", series_mid);
        }
    auto right_res = signal_utils::find_patterns(data->dataR().data()->data);
    logInfo(l) << "Right pulse["<<right_res[0]<<","<<right_res[1]<<"]";
    plot_->setZone(left_res[2],left_res[3],"signal");
    zone = plot_->zone("signal") ;
    zone->setPen( Qt::darkGray );
    zone->setBrush( QColor( "#66FFCC") );

    plot_->replot();

    // сохранение результатов;
    std::vector<std::complex<double>> arr;
    arr.resize(left_res[1]-left_res[0]);
    std::copy(data->dataL().data()->data.begin()+left_res[0],
              data->dataL().data()->data.begin()+left_res[1],
              arr.begin());
    plugin_utils::save_simple_to_file(qApp->applicationDirPath()+"/pattern_pulse.dat",
                                      arr,
                                     (arr.size() / (double)data->dataL().data()->sampleRate));

    arr.resize(left_res[3]-left_res[2]);
    std::copy(data->dataL().data()->data.begin()+left_res[2],
              data->dataL().data()->data.begin()+left_res[3],
              arr.begin());
    plugin_utils::save_simple_to_file(qApp->applicationDirPath()+"/pattern_signal_L.dat",
                                      arr,
                                     (arr.size() / (double)data->dataL().data()->sampleRate));

    std::copy(data->dataR().data()->data.begin()+left_res[2],
              data->dataR().data()->data.begin()+left_res[3],
              arr.begin());
    plugin_utils::save_simple_to_file(qApp->applicationDirPath()+"/pattern_signal_R.dat",
                                      arr,
                                      (arr.size() / (double)data->dataR().data()->sampleRate));
}

void CalcPlotWidget::findBaseTime(const Solutions *solutions)
{
    double mid_base_T_L = 0.;
    double mid_base_T_R = 0.;
    double mid_temp     = 0.;

    for(const auto& ds : solutions->solutions())
        {
            mid_base_T_L += ds.delta_t_signal_L - ds.delta_t_pulse_L;
            mid_base_T_R += ds.delta_t_signal_R - ds.delta_t_pulse_R;
            mid_temp     += ds.temperature;
        }
    mid_base_T_L = mid_base_T_L / solutions->solutions().size();
    mid_base_T_R = mid_base_T_R / solutions->solutions().size();
    mid_temp     = mid_temp     / solutions->solutions().size();

    QVector<QPointF> series;
    double L,V;
    V = plugin_utils::sound_speed(273.15 + mid_temp);

    series.resize(solutions->solutions().size());
    L = V * mid_base_T_L;
    double last_dt = 0.;
    double delta_V = 0.;
    for(decltype(solutions->solutions().size()) i = 0; i < solutions->solutions().size(); ++i )
        {
            const DataObjectSolution& ds = solutions->solutions()[i];
            if( (std::abs(( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - mid_base_T_L) < 0.0000001) ||
                (std::abs(( ds.delta_t_signal_R - ds.delta_t_pulse_R ) - mid_base_T_R) < 0.0000001))
                last_dt = 0.;
            else
                last_dt = (1.0/( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - 1.0/( ds.delta_t_signal_R - ds.delta_t_pulse_R ));
            delta_V = L/2. *  last_dt;

            series[i] = QPointF(i,delta_V);
        }
    plot_->addCurve("mid_base_T_L", series);
    logInfo(l) << "Mid time L = " << QString::number(mid_base_T_L,'f',15);
    logInfo(l) << "L/2.0 = " << QString::number(L/2.,'f',15)
               << "  Dt = " << QString::number(last_dt,'f',15)
               << " delta_V = " <<QString::number(delta_V,'f',15);

    L = V * mid_base_T_R;
    for(decltype(solutions->solutions().size()) i = 0; i < solutions->solutions().size(); ++i )
        {
            const DataObjectSolution& ds = solutions->solutions()[i];
            if( (std::abs(( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - mid_base_T_L) < 0.0000001) ||
                (std::abs(( ds.delta_t_signal_R - ds.delta_t_pulse_R ) - mid_base_T_R) < 0.0000001))
                last_dt = 0.;
            else
                last_dt = (1.0/( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - 1.0/( ds.delta_t_signal_R - ds.delta_t_pulse_R ));
            delta_V = L/2. *  last_dt;
            series[i] = QPointF(i,delta_V);
        }
    plot_->addCurve("mid_base_T_R", series);
    logInfo(l) << "Mid time L = " << QString::number(mid_base_T_R,'f',15);
    logInfo(l) << "L/2.0 = " << QString::number(L/2.,'f',15)
               << "  Dt = " << QString::number(last_dt,'f',15)
               << " delta_V = " <<QString::number(delta_V,'f',15);

    L = V * (mid_base_T_L+mid_base_T_R)/2.0;
    for(decltype(solutions->solutions().size()) i = 0; i < solutions->solutions().size(); ++i )
        {
            const DataObjectSolution& ds = solutions->solutions()[i];
            if( (std::abs(( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - mid_base_T_L) < 0.0000001) ||
                (std::abs(( ds.delta_t_signal_R - ds.delta_t_pulse_R ) - mid_base_T_R) < 0.0000001))
                last_dt = 0.;
            else
                last_dt = (1.0/( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - 1.0/( ds.delta_t_signal_R - ds.delta_t_pulse_R ));
            delta_V = L/2. *  last_dt;
            series[i] = QPointF(i,delta_V);
        }
    plot_->addCurve("mid_base_T", series);
    logInfo(l) << "Mid time  = " << QString::number((mid_base_T_L+mid_base_T_R)/2.0,'f',15);
    logInfo(l) << "L/2.0 = " << QString::number(L/2.,'f',15)
               << "  Dt = " << QString::number(last_dt,'f',15)
               << " delta_V = " <<QString::number(delta_V,'f',15);

    for(decltype(solutions->solutions().size()) i = 0; i < solutions->solutions().size(); ++i )
        {
            const DataObjectSolution& ds = solutions->solutions()[i];
            series[i] = QPointF(i,std::abs(( ds.delta_t_signal_L - ds.delta_t_pulse_L ) - mid_base_T_L));
        }
    plot_->addCurve("mid_base_T_L Dif", series);
    for(decltype(solutions->solutions().size()) i = 0; i < solutions->solutions().size(); ++i )
        {
            const DataObjectSolution& ds = solutions->solutions()[i];
            series[i] = QPointF(i,std::abs(( ds.delta_t_signal_R - ds.delta_t_pulse_R ) - mid_base_T_R));
        }
    plot_->addCurve("mid_base_T_R Dif", series);

    plot_->replot();
}

void CalcPlotWidget::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
        case QEvent::LanguageChange:
            ui->retranslateUi(this);
            break;
        default:
            break;
        }
}
